<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\command;

use app\enum\CommandEnum;
use app\enum\CommonEnum;
use app\enum\KuaiShouEnum;
use app\model\ClientAccountModel;
use app\model\ClientAccountOperationModel;
use app\model\KsAdvertiserHourlyReportExtModel;
use app\model\KsAdvertiserHourlyReportModel;
use app\model\ProjectAccountModel;
use app\service\client\AccountService;
use app\service\kuaishou\FinanceService;
use think\console\Input;
use think\console\Output;
use think\facade\Cache;
use think\facade\Db;

class KsAdvertiserHourlyReportWork extends BaseWork
{
    public const REDIS_TASK_KEY = CommandEnum::KS_TASK_LIST_KEY[1];

    public array $clientAccountInfo = [];

    protected function configure()
    {
        // 指令配置
        $this->setName('ks_advertiser_hourly_report_work');
        // 设置参数
        $this->setDescription('拉取快手广告主消耗小时报表脚本');

        // 设置参数
        $this->addArgument('type', null, '方式')    // 天
            ->setHelp('php think ks_advertiser_hourly_report_work [type]');
    }

    protected function execute(Input $input, Output $output)
    {
        set_time_limit(0);
        $output->writeln('=======磁力引擎-账户报表拉取开始' . date('Y-m-d H:i:s', time()) . '=======');
        $type = $input->getArgument('type');
        $redisKey = self::REDIS_TASK_KEY;
        if ($type == 2) {
            $date = date('Y-m-d', strtotime('-1 day'));
        } else {
            $date = date('Y-m-d');
        }
        $redis = Cache::store('redis')->handler();
        $count = 0;
        while (true) {
            if ($count >= 1) {
                break;
            }
            $advertiserId = $redis->lPop($redisKey);
            if ($advertiserId) {
                // 请求接口
                $this->clientAccountInfo = $this->_getClientAccountInfo($advertiserId);
                $page = 0;
                while (true) {
                    $token = AccountService::getToken(CommonEnum::KS_MEDIA, $advertiserId);
                    if (! $token) {
                        break;
                    }
                    ++$page;
                    $result = $this->_getServiceAdvertiserDailyReport($token, $advertiserId, $date, $date, $page);
                    if (! $result) {
                        $err = ['params' => ['token' => $token, 'advertiserId' => $advertiserId, 'startDate' => $date, 'endDate' => $date, 'page' => $page], 'response' => FinanceService::getError(0)];
                        $output->writeln('=======error:' . json_encode($err, JSON_UNESCAPED_UNICODE) . '=======' . PHP_EOL);
                        logss($this->getDescription(), $this->getName(), $err);
                        break;
                    }
                    $list = $result['data']['details'];
                    if (count($list) == 0) {
                        break;
                    }
                    foreach ($list as $v) {
                        $statDate = intval(date('Ymd', strtotime($v['stat_date'])));
                        $time = $v['stat_date'] . ' ' . sprintf('%02d', $v['stat_hour']) . ':00:00';
                        $statDatetime = intval(date('YmdH', strtotime($time)));
                        $statInfo = $this->_getStatInfo($advertiserId, $statDate, $statDatetime);
                        if (! empty($statInfo)) {
                            if (! $this->_isReportDataUpdate($statInfo, $v)) {
                                $this->_updateAdvertiserData($statInfo['id'], $v);
                            }
                        } else {
                            $this->_insertAdvertiserData($advertiserId, $v);
                        }
                    }
                }
                ++$count;
            } else {
                break;
            }
        }
        $output->writeln('=======磁力引擎-账户报表拉取结束' . date('Y-m-d H:i:s', time()) . '=======');
    }

    private function _getServiceAdvertiserDailyReport(string $token = '', string $advertiserId = '', string $startDate = '', string $endDate = '', int $page = 1)
    {
        $headers = [
            'Access-Token' => $token,
            'Content-Type' => 'application/json',
        ];
        $params = [
            'advertiser_id' => $advertiserId,
            'start_date' => $startDate,
            'end_date' => $endDate,
            'temporal_granularity' => 'HOURLY',
            'page' => $page,
            'page_size' => KuaiShouEnum::MAX_ADVERTISER_PAGE_SIZE,
        ];

        return FinanceService::getAdvertiserReport($headers, $params);
    }

    /**
     * 判断是否需要更新.
     * @param array $oldData 旧数据
     * @param array $newData 新数据
     */
    private function _isReportDataUpdate(array $oldData = [], array $newData = []): bool
    {
        $one = $oldData['cost'] == $newData['charge'];

        if ($one) {
            return true;
        }

        return false;
    }

    /**
     * 获取广告账户报表信息.
     * @param string $advertiserId 账户ID
     * @param int $statDate 日期
     * @throws
     */
    private function _getStatInfo(string $advertiserId = '', int $statDate = 0, int $statDatetime = 0): array
    {
        $where = [
            ['stat_date', '=', $statDate],
            ['stat_datetime', '=', $statDatetime],
            ['advertiser_id', '=', $advertiserId],
        ];

        $info = (new KsAdvertiserHourlyReportModel())->where($where)->field(true)->find();
        if (! $info) {
            return [];
        }

        return $info->toArray();
    }

    /**
     * 修改广告报表信息.
     * @param int $id 主键ID
     * @param array $info 信息数据
     */
    private function _updateAdvertiserData(int $id = 0, array $info = []): bool
    {
        try {
            if (! isset($info['photo_signature'])) {
                return false;
            }

            $data = [
                'cost' => $info['charge'],
                'update_time' => time(),
            ];

            $extData = [
                'content' => json_encode($info, JSON_UNESCAPED_UNICODE),
                'update_time' => time(),
            ];

            Db::startTrans();
            $one = (new KsAdvertiserHourlyReportModel())->where('id', $id)->update($data);
            $two = (new KsAdvertiserHourlyReportExtModel())->where('report_id', $id)->update($extData);
            if ($one && $two) {
                Db::commit();
                return true;
            }

            Db::rollback();
            return false;
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 插入广告报表信息.
     * @param string $advertiserId 账户ID
     * @param array $info 信息数据
     */
    private function _insertAdvertiserData(string $advertiserId = '', array $info = []): bool
    {
        try {
            Db::startTrans();
            $time = $info['stat_date'] . ' ' . sprintf('%02d', $info['stat_hour']) . ':00:00';
            $statDatetime = intval(date('YmdH', strtotime($time)));
            $statDate = date('Ymd', strtotime($info['stat_date']));
            $data = [
                'company_id' => $this->clientAccountInfo['company_id'],
                'client_id' => $this->clientAccountInfo['client_id'],
                'advertiser_id' => $advertiserId,
                'account_id' => $this->clientAccountInfo['id'],
                'project_id' => $this->clientAccountInfo['project_id'],
                'staff_id' => $this->clientAccountInfo['staff_id'],
                'stat_date' => $statDate,
                'stat_datetime' => $statDatetime,
                'cost' => $info['charge'],
                'create_time' => time(),
            ];
            $insertId = (new KsAdvertiserHourlyReportModel())->insertGetId($data);

            if ($insertId <= 0) {
                Db::rollback();
                return false;
            }

            $extData = [
                'company_id' => $this->clientAccountInfo['company_id'],
                'client_id' => $this->clientAccountInfo['client_id'],
                'account_id' => $this->clientAccountInfo['id'],
                'report_id' => $insertId,
                'advertiser_id' => $advertiserId,
                'stat_date' => $statDate,
                'stat_datetime' => $statDatetime,
                'content' => json_encode($info, JSON_UNESCAPED_UNICODE),
                'create_time' => time(),
            ];

            $extInsertId = (new KsAdvertiserHourlyReportExtModel())->insertGetId($extData);

            if ($extInsertId <= 0) {
                Db::rollback();
                return false;
            }

            Db::commit();
            return true;
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 获取账户信息.
     * @param string $advertiserId 账户ID
     * @throws
     */
    private function _getClientAccountInfo(string $advertiserId = ''): array
    {
        $info = (new ClientAccountModel())->where('advertiser_id', $advertiserId)->field(true)->find();
        if (! $info) {
            return [];
        }
        $info = $info->toArray();
        // 查询账户运营
        $staffId = ClientAccountOperationModel::where('advertiser_id', $advertiserId)->value('staff_id');
        $projectId = ProjectAccountModel::where('account_id', $info['id'])->value('project_id');
        $info['staff_id'] = $staffId ?: 0;
        $info['project_id'] = $projectId ?: 0;
        return $info;
    }
}
